Skip to content

Commit b9acbb2

Browse files
authored
Support reporting connection count for incoming Internet connections (#297)
1 parent cd59536 commit b9acbb2

File tree

12 files changed

+338
-122
lines changed

12 files changed

+338
-122
lines changed

src/mapper/pkg/cloudclient/generated.go

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/mapper/pkg/cloudclient/schema.graphql

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ directive @constraint(
77
example: String!
88
) on ENUM_VALUE
99

10-
"""The @defer directive may be specified on a fragment spread to imply de-prioritization, that causes the fragment to be omitted in the initial response, and delivered as a subsequent response afterward. A query with @defer directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred delivered in a subsequent response. @include and @skip take precedence over @defer."""
10+
"""Directs the executor to defer this fragment when the `if` argument is true or undefined."""
1111
directive @defer(
12+
"""Deferred when true or undefined."""
1213
if: Boolean
14+
"""Unique name"""
1315
label: String
1416
) on FRAGMENT_SPREAD | INLINE_FRAGMENT
1517

16-
"""The @deprecated built-in directive is used within the type system definition language to indicate deprecated portions of a GraphQL service's schema, such as deprecated fields on a type, arguments on a field, input fields on an input type, or values of an enum type."""
18+
"""Marks an element of a GraphQL schema as no longer supported."""
1719
directive @deprecated(
20+
"""Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/)."""
1821
reason: String
1922
) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE
2023

@@ -27,8 +30,9 @@ directive @httpError(
2730
statusCode: Int!
2831
) on ENUM_VALUE
2932

30-
"""The @include directive may be provided for fields, fragment spreads, and inline fragments, and allows for conditional inclusion during execution as described by the if argument."""
33+
"""Directs the executor to include this field or fragment only when the `if` argument is true."""
3134
directive @include(
35+
"""Included when true."""
3236
if: Boolean!
3337
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
3438

@@ -41,6 +45,9 @@ user authentication, meaning anyone and everyone can execute it. USE WITH CAUTIO
4145
user authentication, meaning anyone and everyone can execute it. USE WITH CAUTION."""
4246
directive @noauth on FIELD_DEFINITION
4347

48+
"""Indicates exactly one field must be supplied and this field must not be `null`."""
49+
directive @oneOf on INPUT_OBJECT
50+
4451
"""@requiresRole indicates that the specified query / mutation / subscription requires any of the provided roles to be executed.
4552
Users without any of the specified roles will not be able to execute the query / mutation / subscription."""
4653
directive @requiresRole(
@@ -57,13 +64,15 @@ directive @restApiRoute(
5764
tags: [String!]!
5865
) on FIELD_DEFINITION
5966

60-
"""The @skip directive may be provided for fields, fragment spreads, and inline fragments, and allows for conditional exclusion during execution as described by the if argument."""
67+
"""Directs the executor to skip this field or fragment when the `if` argument is true."""
6168
directive @skip(
69+
"""Skipped when true."""
6270
if: Boolean!
6371
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
6472

65-
"""The @specifiedBy built-in directive is used within the type system definition language to provide a scalar specification URL for specifying the behavior of custom scalar types."""
73+
"""Exposes a URL that specifies the behavior of this scalar."""
6674
directive @specifiedBy(
75+
"""The URL that specifies the behavior of this scalar."""
6776
url: String!
6877
) on SCALAR
6978

@@ -726,6 +735,8 @@ enum EdgeAccessStatusReason {
726735
ALLOWED_BY_APPLIED_INTENTS_KAFKA_OVERLY_PERMISSIVE
727736
ALLOWED_BY_APPLIED_INTENTS_DATABASE_OVERLY_PERMISSIVE
728737
ALLOWED_BY_EXTERNAL_TRAFFIC_NETWORK_POLICY
738+
ALLOWED_BY_INTERNET_EGRESS_NETWORK_POLICY
739+
ALLOWED_BY_INTERNET_INGRESS_NETWORK_POLICY
729740
WOULD_BE_ALLOWED_BY_EXTERNAL_TRAFFIC_NETWORK_POLICY
730741
BLOCKED_BY_APPLIED_INTENTS_UNDER_PERMISSIVE
731742
BLOCKED_BY_APPLIED_INTENTS_RESOURCE_MISMATCH
@@ -737,6 +748,8 @@ enum EdgeAccessStatusReason {
737748
BLOCKED_BY_APPLIED_INTENTS_DATABASE_UNDER_PERMISSIVE
738749
BLOCKED_BY_APPLIED_INTENTS_DATABASE_RESOURCE_MISMATCH
739750
BLOCKED_BY_DATABASE_ENFORCEMENT_CONFIG_MISSING_APPLIED_INTENTS
751+
BLOCKED_BY_INTERNET_EGRESS_NETWORK_POLICY
752+
BLOCKED_BY_INTERNET_INGRESS_NETWORK_POLICY
740753
BLOCKED_BY_DEFAULT_DENY
741754
SHARED_SERVICE_ACCOUNT
742755
CLIENT_ISTIO_SIDECAR_MISSING
@@ -1085,6 +1098,12 @@ enum IPFamily {
10851098
UNKNOWN
10861099
}
10871100

1101+
"""IP filters"""
1102+
type IPFilterValue {
1103+
cidr: String!
1104+
exclude: [String!]
1105+
}
1106+
10881107
input IncomingInternetSourceInput {
10891108
ip: String!
10901109
}
@@ -1098,6 +1117,7 @@ input IncomingTrafficIntentInput {
10981117
serverName: String!
10991118
namespace: String!
11001119
source: IncomingInternetSourceInput!
1120+
connectionsCount: ConnectionsCount
11011121
}
11021122

11031123
input IngressControllerConfigInput {
@@ -2288,6 +2308,7 @@ type NetworkPolicy {
22882308
workloadsAffected: Int!
22892309
spec: String!
22902310
lastUsed: Time
2311+
metadata: NetworkPolicyMetadata
22912312
}
22922313

22932314
input NetworkPolicyInput {
@@ -2302,6 +2323,12 @@ enum NetworkPolicyKind {
23022323
CILIUM_CLUSTER_WIDE_NETWORK_POLICY
23032324
}
23042325

2326+
type NetworkPolicyMetadata {
2327+
isEgress: Boolean!
2328+
isIngress: Boolean!
2329+
hasIpBlocks: Boolean!
2330+
}
2331+
23052332
enum NetworkPolicyScope {
23062333
PRIMARY
23072334
EGRESS

src/mapper/pkg/clouduploader/cloud_upload.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ func (c *CloudUploader) NotifyIncomingTrafficIntents(ctx context.Context, intent
184184
},
185185
},
186186
}
187+
if intent.ConnectionsCount != nil {
188+
output.Intent.ConnectionsCount = nilable.FromPtr(intent.ConnectionsCount)
189+
}
187190
return output
188191
})
189192

src/mapper/pkg/clouduploader/cloud_uploader_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"github.com/otterize/network-mapper/src/mapper/pkg/awsintentsholder"
77
"github.com/otterize/network-mapper/src/mapper/pkg/incomingtrafficholder"
8+
"github.com/otterize/nilable"
89
"testing"
910
"time"
1011

@@ -118,6 +119,7 @@ func (s *CloudUploaderTestSuite) TestUploadIncomingTrafficIntents() {
118119
Server: model.OtterizeServiceIdentity{Name: "server1", Namespace: s.testNamespace},
119120
LastSeen: testTimestamp,
120121
IP: sourceIP,
122+
SrcPorts: []int64{10},
121123
}
122124
s.incomingHolder.AddIntent(incomingIntent)
123125

@@ -130,6 +132,7 @@ func (s *CloudUploaderTestSuite) TestUploadIncomingTrafficIntents() {
130132
Source: cloudclient.IncomingInternetSourceInput{
131133
Ip: sourceIP,
132134
},
135+
ConnectionsCount: nilable.From(cloudclient.ConnectionsCount{Current: lo.ToPtr(1), Added: lo.ToPtr(1), Removed: lo.ToPtr(0)}),
133136
},
134137
},
135138
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package concurrentconnectioncounter
2+
3+
import (
4+
"github.com/otterize/network-mapper/src/mapper/pkg/cloudclient"
5+
"github.com/samber/lo"
6+
)
7+
8+
type ConnectionCounterMap[K comparable, Countable CountableIntent] map[K]*ConnectionCounter[Countable]
9+
10+
type ConnectionCountDiffer[K comparable, Countable CountableIntent] struct {
11+
currentCounters ConnectionCounterMap[K, Countable]
12+
previousCounters ConnectionCounterMap[K, Countable]
13+
}
14+
15+
func NewConnectionCountDiffer[K comparable, Countable CountableIntent]() *ConnectionCountDiffer[K, Countable] {
16+
return &ConnectionCountDiffer[K, Countable]{
17+
currentCounters: make(ConnectionCounterMap[K, Countable]),
18+
previousCounters: make(ConnectionCounterMap[K, Countable]),
19+
}
20+
}
21+
22+
func (c *ConnectionCountDiffer[K, Countable]) Reset() {
23+
c.previousCounters = c.currentCounters
24+
c.currentCounters = make(ConnectionCounterMap[K, Countable])
25+
}
26+
27+
func (c *ConnectionCountDiffer[K, Countable]) Increment(key K, counterInput CounterInput[Countable]) {
28+
29+
_, existingCounterFound := c.currentCounters[key]
30+
if !existingCounterFound {
31+
c.currentCounters[key] = NewConnectionCounter[Countable]()
32+
}
33+
34+
c.currentCounters[key].AddConnection(counterInput)
35+
}
36+
37+
func (c *ConnectionCountDiffer[K, Countable]) GetDiff(key K) (cloudclient.ConnectionsCount, bool) {
38+
currentCounter, hasCurrentValue := c.currentCounters[key]
39+
prevCounter, hasPrevValue := c.previousCounters[key]
40+
41+
if hasCurrentValue && !hasPrevValue {
42+
connectionsCount, isValid := currentCounter.GetConnectionCount()
43+
if isValid {
44+
return cloudclient.ConnectionsCount{
45+
Current: lo.ToPtr(connectionsCount),
46+
Added: lo.ToPtr(connectionsCount),
47+
Removed: lo.ToPtr(0),
48+
}, true
49+
}
50+
return cloudclient.ConnectionsCount{}, false
51+
}
52+
53+
if !hasCurrentValue && hasPrevValue {
54+
connectionsCount, isValid := prevCounter.GetConnectionCount()
55+
if isValid {
56+
return cloudclient.ConnectionsCount{
57+
Current: lo.ToPtr(0),
58+
Added: lo.ToPtr(0),
59+
Removed: lo.ToPtr(connectionsCount),
60+
}, true
61+
}
62+
return cloudclient.ConnectionsCount{}, false
63+
}
64+
65+
if hasCurrentValue && hasPrevValue {
66+
connectionDiff, valid := currentCounter.GetConnectionCountDiff(prevCounter)
67+
if valid {
68+
return connectionDiff, true
69+
}
70+
}
71+
72+
return cloudclient.ConnectionsCount{}, false
73+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package concurrentconnectioncounter
2+
3+
import (
4+
"github.com/stretchr/testify/suite"
5+
"testing"
6+
)
7+
8+
type ConnectionCountDifferSuite struct {
9+
suite.Suite
10+
}
11+
12+
type CountableIntentTCPDummy struct{}
13+
type CountableIntentDNSDummy struct{}
14+
15+
func NewCountableIntentDummy() *CountableIntentTCPDummy {
16+
return &CountableIntentTCPDummy{}
17+
}
18+
19+
func (c *CountableIntentTCPDummy) ShouldCountUsingSrcPortMethod() bool {
20+
return true
21+
}
22+
23+
func (c *CountableIntentTCPDummy) ShouldCountUsingDNSMethod() bool {
24+
return false
25+
}
26+
27+
func NewCountableIntentDNSDummy() *CountableIntentDNSDummy {
28+
return &CountableIntentDNSDummy{}
29+
}
30+
31+
func (c *CountableIntentDNSDummy) ShouldCountUsingSrcPortMethod() bool {
32+
return false
33+
}
34+
35+
func (c *CountableIntentDNSDummy) ShouldCountUsingDNSMethod() bool {
36+
return true
37+
}
38+
39+
func (s *ConnectionCountDifferSuite) TestTCPDiff_TestNoPrevValue() {
40+
differ := NewConnectionCountDiffer[string, *CountableIntentTCPDummy]()
41+
42+
// Add a connections
43+
differ.Increment("key1", CounterInput[*CountableIntentTCPDummy]{
44+
Intent: NewCountableIntentDummy(),
45+
SourcePorts: []int64{1, 2},
46+
})
47+
differ.Increment("key1", CounterInput[*CountableIntentTCPDummy]{
48+
Intent: NewCountableIntentDummy(),
49+
SourcePorts: []int64{2, 3},
50+
})
51+
52+
// Get the diff
53+
diff, ok := differ.GetDiff("key1")
54+
55+
s.Require().True(ok)
56+
s.Require().Equal(3, *diff.Current)
57+
s.Require().Equal(3, *diff.Added)
58+
s.Require().Equal(0, *diff.Removed)
59+
}
60+
61+
func (s *ConnectionCountDifferSuite) TestTCPDiff_TestPrevConnectionsAreTheSameAsCurrent() {
62+
differ := NewConnectionCountDiffer[string, *CountableIntentTCPDummy]()
63+
64+
// Add a connections
65+
differ.Increment("key1", CounterInput[*CountableIntentTCPDummy]{
66+
Intent: NewCountableIntentDummy(),
67+
SourcePorts: []int64{1, 2, 3},
68+
})
69+
70+
differ.Reset()
71+
72+
// Add same connections
73+
differ.Increment("key1", CounterInput[*CountableIntentTCPDummy]{
74+
Intent: NewCountableIntentDummy(),
75+
SourcePorts: []int64{1, 2, 3},
76+
})
77+
78+
// Get the diff
79+
diff, ok := differ.GetDiff("key1")
80+
81+
s.Require().True(ok)
82+
s.Require().Equal(3, *diff.Current)
83+
s.Require().Equal(0, *diff.Added)
84+
s.Require().Equal(0, *diff.Removed)
85+
}
86+
87+
func (s *ConnectionCountDifferSuite) TestDNSDiff_TestNoPrevValue() {
88+
differ := NewConnectionCountDiffer[string, *CountableIntentDNSDummy]()
89+
90+
// Add a connections
91+
differ.Increment("key1", CounterInput[*CountableIntentDNSDummy]{
92+
Intent: NewCountableIntentDNSDummy(),
93+
SourcePorts: []int64{1, 2},
94+
})
95+
differ.Increment("key1", CounterInput[*CountableIntentDNSDummy]{
96+
Intent: NewCountableIntentDNSDummy(),
97+
SourcePorts: []int64{2, 3},
98+
})
99+
100+
// Get the diff
101+
diff, ok := differ.GetDiff("key1")
102+
103+
s.Require().True(ok)
104+
s.Require().Equal(2, *diff.Current)
105+
s.Require().Equal(2, *diff.Added)
106+
s.Require().Equal(0, *diff.Removed)
107+
}
108+
109+
func (s *ConnectionCountDifferSuite) TestDNSDiff_TestWithPrevValue() {
110+
differ := NewConnectionCountDiffer[string, *CountableIntentDNSDummy]()
111+
112+
// Add a connections
113+
differ.Increment("key1", CounterInput[*CountableIntentDNSDummy]{
114+
Intent: NewCountableIntentDNSDummy(),
115+
SourcePorts: []int64{1, 2},
116+
})
117+
differ.Increment("key1", CounterInput[*CountableIntentDNSDummy]{
118+
Intent: NewCountableIntentDNSDummy(),
119+
SourcePorts: []int64{2, 3},
120+
})
121+
122+
differ.Reset()
123+
124+
differ.Increment("key1", CounterInput[*CountableIntentDNSDummy]{
125+
Intent: NewCountableIntentDNSDummy(),
126+
SourcePorts: make([]int64, 0),
127+
})
128+
129+
// Get the diff
130+
diff, ok := differ.GetDiff("key1")
131+
132+
s.Require().True(ok)
133+
s.Require().Equal(1, *diff.Current)
134+
s.Require().Equal(1, *diff.Added)
135+
s.Require().Equal(2, *diff.Removed)
136+
}
137+
138+
func TestConnectionCountDifferSuite(t *testing.T) {
139+
suite.Run(t, new(ConnectionCountDifferSuite))
140+
}

0 commit comments

Comments
 (0)